
#ifndef TOKZRGENTR_GEN_TOKENIZERWRAPPER_H
#define TOKZRGENTR_GEN_TOKENIZERWRAPPER_H

//#	This class is wrapping all the target data structure in the generated tokenizer.h
//#	Using this class to build a tokenizer directly in memory --
//#	without generate the .h\.cpp file and rebuild the tokenizer.h
//#	Using this class for testing the target tokenizer.h

//#	author:@Mapupcal all right reserved.
#include"regex_parser.h"
#include"char_set_table.h"
#include"tokenizer_datas.h"
#include"internal_tokenizer.h"
#include"output_templates.h"
#include<string>
#include<map>
#include<vector>
namespace TokzrGentr
{
	class tokenizer_wrapper
	{
	private:
		std::map<unsigned, 
			std::set<std::pair<u16string,std::shared_ptr<regex_node>>>> _ranks;	//#	For infomation collecting.
		std::vector<std::u16string> _tokens_identifiers;			//#	For Indentifying which token is regonized.
		std::shared_ptr<internal_tokenizer> _tokzr_sptr;
		std::shared_ptr<char_sets_table> _charset_table_sptr;
		std::shared_ptr<connected_table> _connected_table_sptr;
		unsigned rule_num;
	public:
		tokenizer_wrapper() {
			rule_num = 0;
			_charset_table_sptr = std::make_shared<char_sets_table>();
		}
		tokenizer_wrapper &AddRule(const u16string_ref & id, const u16string_ref &re, unsigned rank = 0)
		{
			ASSERT(_tokzr_sptr.get() == nullptr);	//#	This wrapper is not builded
			ASSERT_MSG(!_charset_table_sptr->is_constructed(), "Hadn't Constructed The Char Set Table.");

			regex_parser re_parser(re);
			auto re_node_ptr = re_parser.tree_root();//# caching the regex parsing tree for later use.
			
			ASSERT(!re_parser.is_fail());	//#Check whether the regex is vailed

			//# Spclit the char sets table
			splict_chars_set_table_al al(_charset_table_sptr.get());
			al.Splict(re_node_ptr.get());

			if (_ranks.find(rank) == _ranks.end())
				_ranks.insert({ rank,{{id.as_u16string(),re_node_ptr}} });
			else
				_ranks[rank].insert({ id.as_u16string(),re_node_ptr });
			rule_num++;
			return *this;
		}
		std::shared_ptr<internal_tokenizer> Build()
		{
			if (_tokzr_sptr.get() != nullptr)
				return _tokzr_sptr;
			//#Construct the char_set_table object
			_charset_table_sptr->construct();

			//# For chaching the dfa
			std::set<dfa> dfas;
			unsigned current_index_of_tokens = 1;

			//# serialization and build for dfa
			_tokens_identifiers.reserve(rule_num + 1);
			_tokens_identifiers.push_back(u"");
			for (auto r : _ranks)
			{
				for (auto p : r.second)
				{
					_tokens_identifiers.push_back(p.first);
					//#Generate Thompson automatics
					regex_automatics_gen gen;
					auto nfa_tmp = gen.Call(p.second.get());
					auto nfa_target = nfa_cstr::build_nfa(nfa_tmp, current_index_of_tokens);
					current_index_of_tokens++;
					//#Generator dfa automatics using subset construct algorithms
					auto dfa_taget = dfa_cstr::subset_construct(nfa_target, _charset_table_sptr.get());
					//#Free the nfa
					nfa_alloc::free(nfa_target);
					dfas.insert(dfa_taget);
				}
			}

			auto target_dfa = dfa_cstr::subset_construct(dfas, _charset_table_sptr.get());
			_connected_table_sptr = std::shared_ptr<connected_table>(connected_table::parse_from(target_dfa));
			
			_tokzr_sptr = std::make_shared<internal_tokenizer>(
				_connected_table_sptr,
				_charset_table_sptr,
				_tokens_identifiers);
			
			//# Free all the datas
			for_each(dfas.begin(), dfas.end(), [](dfa target) {
				dfa_alloc::free(target);
			});

			dfa_alloc::free(target_dfa);
			
			return _tokzr_sptr;
		}
		//TODO:
		std::u16string BuildAsOutputFile(BaseOutputTemplate *OutputTemplate) 
		{
			if (_tokzr_sptr.get() == nullptr)
				Build();
			return OutputTemplate->Dump(_tokzr_sptr.get());
		}
	};
}

#endif